home *** CD-ROM | disk | FTP | other *** search
/ Delphi Informant Complete 1995 - 2000 / Delphi Informant Complete 1995 to 2000.iso / Delphi Informant Magazine Complete Works SOURCE CODE 1998.rar / 1998 / Jul / di9807rl / moving.pas < prev    next >
Pascal/Delphi Source File  |  1998-02-24  |  5KB  |  183 lines

  1. unit Moving;
  2.  
  3. { Demostration of palettes and animation in a Delphi component.
  4.   Copyright ⌐ 1998 Tempest Software, Inc.
  5.  
  6.   The TMovingGradient component displays a color gradient, with
  7.   a user-specified starting and ending color, and number of
  8.   color steps between them.
  9.  
  10.   When Enabled, the gradient continually rotates, which has the
  11.   effect of moving sideways. Set Enabled to False to stop
  12.   the animation effect. Palette animation works only on
  13.   displays that use a palette, namely, 256-color video adapters.
  14.  
  15.   One possible use for this "non-progress" bar is to show that a
  16.   process is running but you don't know when it will finish.
  17. }
  18.  
  19. interface
  20.  
  21. uses
  22.   SysUtils, Windows, Messages, Classes, Graphics, Controls, ExtCtrls, Gradient;
  23.  
  24. type
  25.   TMovingGradient = class(TGradient)
  26.   private
  27.     // Timer for animating the palette
  28.     fTimer: TTimer;
  29.  
  30.     procedure SetInterval(Value: Cardinal);
  31.     function GetInterval: Cardinal;
  32.     procedure CmEnabledChanged(var Msg: TWmNoParams); message Cm_EnabledChanged;
  33.   protected
  34.     procedure Animate(Sender: TObject); virtual;
  35.     procedure GetColor(var Red, Green, Blue: Byte; Index: Integer); override;
  36.     function MakePalette: HPalette; override;
  37.     procedure ShiftColors; virtual;
  38.   public
  39.     constructor Create(Owner: TComponent); override;
  40.   published
  41.     property Enabled;
  42.     property Height default 20;
  43.     property ColorBottom default clWhite;
  44.     property Interval: Cardinal read GetInterval write SetInterval default 100;
  45.   end;
  46.  
  47. procedure Register;
  48.  
  49. implementation                         
  50.  
  51. // Create and initialize the control. Start with 64 steps
  52. // because most palette devices use 18 bits per pixel,
  53. // which means 6 bits per color, or 64 distinct colors.
  54. // The colors blue and white look nice, but feel free to
  55. // change them to whatever you find more aesthetic.
  56. // Ditto for the default size.
  57. constructor TMovingGradient.Create(Owner: TComponent);
  58. begin
  59.   inherited Create(Owner);
  60.  
  61.   fTimer := TTimer.Create(Self);
  62.   fTimer.Enabled := not (csDesigning in ComponentState);
  63.   fTimer.OnTimer := Animate;
  64.   fTimer.Interval := 100;
  65.  
  66.   ColorBottom := clWhite;
  67.   Height := 20;
  68. end;
  69.  
  70. // Compute a color for the gradient.
  71. procedure TMovingGradient.GetColor(var Red, Green, Blue: Byte; Index: Integer);
  72. var
  73.   Top, Bottom: TColor;
  74. begin
  75.   Top := ColorToRgb(ColorTop);
  76.   Bottom := ColorToRgb(ColorBottom);
  77.   if Index >= NumColors then
  78.     Index := LogPalette.palNumEntries - Index - 1;
  79.  
  80.   Red   :=
  81.     MulDiv(NumColors-Index-1, GetRValue(Top), NumColors-1) +
  82.     MulDiv(Index, GetRValue(Bottom), NumColors-1);
  83.  
  84.   Green :=
  85.     MulDiv(NumColors-Index-1, GetGValue(Top), NumColors-1) +
  86.     MulDiv(Index, GetGValue(Bottom), NumColors-1);
  87.  
  88.   Blue  :=
  89.     MulDiv(NumColors-Index-1, GetBValue(Top), NumColors-1) +
  90.     MulDiv(Index, GetBValue(Bottom), NumColors-1);
  91. end;
  92.  
  93. // Make a gradient palette and return the palette handle.
  94. // Call this once when initializing the control.
  95. // If the user changes the number of steps or the colors,
  96. // recreate the palette with the new information.
  97. function TMovingGradient.MakePalette: HPalette;
  98. var
  99.   I: Integer;
  100. begin
  101.   AllocatePalette(NumColors * 2);
  102.  
  103.   // To provide a smooth visual transition when rotating the palette,
  104.   // make the gradient go up and down, so the gradient has twice as
  105.   // many bands as it has distinct colors.
  106.  
  107.   {$R- Turn off range checking to access palette entries.}
  108.   for I := 0 to LogPalette.palNumEntries-1 do
  109.     with LogPalette.palPalEntry[I] do
  110.     begin
  111.       GetColor(peRed, peGreen, peBlue, I);
  112.       if csDesigning in ComponentState then
  113.         peFlags := 0
  114.       else
  115.         peFlags := PC_Reserved;
  116.     end;
  117.   {$R+}
  118.  
  119.   Result := CreatePalette(LogPalette^);
  120. end;
  121.  
  122. // Shift the colors to animate the palette. Just rotate all the colors
  123. // in the palette by one step.
  124. procedure TMovingGradient.ShiftColors;
  125. var
  126.   Tmp: TPaletteEntry;
  127.   I: Integer;
  128. begin
  129.   Assert(LogPalette <> nil);
  130.  
  131. {$R-}
  132.   Tmp := LogPalette.palPalEntry[0];
  133.   for I := 0 to LogPalette.palNumEntries-2 do
  134.     LogPalette.palPalEntry[I] := LogPalette.palPalEntry[I+1];
  135.   LogPalette.palPalEntry[LogPalette.palNumEntries-1] := Tmp;
  136. {$R+}
  137. end;
  138.  
  139. // Animate the control by shifting the colors and then telling
  140. // Windows to use the new colors.
  141. procedure TMovingGradient.Animate(Sender: TObject);
  142. var
  143.   OldPal: HPalette;
  144. begin
  145.   GetPalette; // Make sure the palette has been created.
  146.   ShiftColors;
  147.  
  148.   OldPal := SelectPalette(Canvas.Handle, Palette, False);
  149.   try
  150.     AnimatePalette(Palette, 0, LogPalette.palNumEntries, @LogPalette.palPalEntry[0]);
  151.   finally
  152.     SelectPalette(Canvas.Handle, OldPal, False);
  153.   end;
  154. end;
  155.  
  156. // Propagate changes to the Enabled property to the timer, but
  157. // at design time, leave the timer disabled.
  158. procedure TMovingGradient.CmEnabledChanged(var Msg: TWmNoParams);
  159. begin
  160.   fTimer.Enabled := Enabled and not (csDesigning in ComponentState);
  161.   inherited;
  162. end;
  163.  
  164. // Propagate changes to the update interval to the timer.
  165. procedure TMovingGradient.SetInterval(Value: Cardinal);
  166. begin
  167.   fTimer.Interval := Value
  168. end;
  169.  
  170. // Get the interval from the timer.
  171. function TMovingGradient.GetInterval: Cardinal;
  172. begin
  173.   Result := fTimer.Interval
  174. end;
  175.  
  176.  
  177. procedure Register;
  178. begin
  179.   RegisterComponents('Tempest', [TMovingGradient]);
  180. end;
  181.  
  182. end.
  183.